package main

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"time"
)

func main() {
	// 实例化路由对象
	r := gin.Default()
	// 10.全局使用中间件
	r.Use(StatCost())
	// 1.实现restful-api && 为单个路由注册中间件
	r.GET("/book", StatCost(), func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "GET",
		})
	})
	r.POST("/book", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "POST",
		})
	})
	r.PUT("/book", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "PUT",
		})
	})
	r.DELETE("/book", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "DELETE",
		})
	})
	//2使用json response
	// 2.1 自己构建json
	r.GET("/use_json", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "json response",
		})
	})

	// 2.2 使用结构体
	r.GET("/use_json2", func(c *gin.Context) {

		var msg struct {
			Name    string `json:user`
			Message string
			Age     int
		}
		msg.Name = "zhangsan"
		msg.Message = "hello"
		msg.Age = 18
		c.JSON(200, msg)
	})

	// 3.获取query string
	r.GET("/test_query", func(c *gin.Context) {
		//name := c.Query("username") //获取url的参数
		name := c.DefaultQuery("username", "zhangsan") //获取url的参数设置默认值
		fmt.Println("name:" + name)
		c.JSON(http.StatusOK, gin.H{
			"message": name,
		})
	})

	// 4.获取表单参数
	r.POST("/test_form", func(c *gin.Context) {
		username := c.PostForm("username")
		password := c.PostForm("password")
		c.JSON(http.StatusOK, gin.H{
			"username": username,
			"password": password,
		})
	})

	// 5.获取路劲参数
	r.POST("/test_param/:username", func(c *gin.Context) {
		username := c.Param("username")
		c.JSON(http.StatusOK, gin.H{
			"username": username,
		})
	})

	// 6.获取application/json参数
	r.POST("/test_json", func(c *gin.Context) {
		// 注意：下面为了举例子方便，暂时忽略了错误处理
		b, _ := c.GetRawData() // 从c.Request.Body读取请求数据
		// 定义map或结构体
		var m map[string]interface{}
		// 反序列化
		_ = json.Unmarshal(b, &m)
		c.JSON(http.StatusOK, m)
	})

	// 7.参数绑定
	// 定义一个参数的结构体 类比fastapi中的schema
	type Login struct {
		User     string `form:"user" json:"user" binding:"required"`
		Password string `form:"password" json:"password" binding:"required"`
	}
	// 绑定JSON的示例 ({"user": "q1mi", "password": "123456"})
	r.POST("/login", func(c *gin.Context) {
		var login Login
		//ShouldBind会根据content-type自己选择绑定
		if err := c.ShouldBindJSON(&login); err == nil {
			fmt.Printf("login info:%#v\n", login)
			c.JSON(http.StatusOK, gin.H{
				"user":     login.User,
				"password": login.Password,
			})
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})

	// 8.gin 路由组 在项目实战中感觉可以定义路由组来在apps/app/router中导入路由写路由
	UserGroup := r.Group("/user")
	{
		UserGroup.GET("/login", func(ctx *gin.Context) {
			ctx.JSON(http.StatusOK, gin.H{
				"message": "获取用户信息",
			})
		})
		UserGroup.POST("/login", func(ctx *gin.Context) {
			ctx.JSON(http.StatusOK, gin.H{
				"message": "用户登陆",
			})
		})
	}
}

//	9.编写中间件
// StatCost 是一个统计耗时请求耗时的中间件
func StatCost() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		c.Set("name", "小王子") // 可以通过c.Set在请求上下文中设置值，后续的处理函数能够取到该值
		// 调用该请求的剩余处理程序
		c.Next()
		// 不调用该请求的剩余处理程序
		// c.Abort()
		// 计算耗时
		cost := time.Since(start)
		log.Println(cost)
	}
}
